package org.zoomdev.zoom;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.util.TraceClassVisitor;

import java.io.PrintWriter;
import java.lang.reflect.Method;

public class ComplexAddGenerator {

    public static void main(String[] args) throws Exception {
        // 1. 生成类字节码
        byte[] bytecode = generateComplexAddClass();

        // 2. 加载生成的类
        Class<?> generatedClass = loadClass("com.example.ComplexCalculator", bytecode);

        // 3. 获取并调用add方法
        Method addMethod = generatedClass.getDeclaredMethod("add", int.class, int.class);

        // 4. 测试方法
        int result = (int) addMethod.invoke(null, 8, 12); // 静态方法调用
        System.out.println("8 + 12 = " + result); // 输出: 8 + 12 = 20

        // 5. 打印生成的字节码
        printBytecode(bytecode);
    }

    /**
     * 生成包含复杂add方法的类字节码
     */
    private static byte[] generateComplexAddClass() {
        // 创建ClassWriter，自动计算栈帧和局部变量表大小
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);

        // 定义类
        cw.visit(Opcodes.V1_8,
                Opcodes.ACC_PUBLIC,
                "com/example/ComplexCalculator",
                null,
                "java/lang/Object",
                null);

        // 生成默认构造函数
        generateConstructor(cw);

        // 生成复杂的add方法
        generateComplexAddMethod(cw);

        // 完成类定义
        cw.visitEnd();

        return cw.toByteArray();
    }

    /**
     * 生成默认构造函数
     */
    private static void generateConstructor(ClassWriter cw) {
        MethodVisitor mv = cw.visitMethod(
                Opcodes.ACC_PUBLIC,
                "<init>",
                "()V",
                null,
                null
        );

        mv.visitCode();
        // 调用父类(Object)构造函数
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitMethodInsn(
                Opcodes.INVOKESPECIAL,
                "java/lang/Object",
                "<init>",
                "()V",
                false
        );
        mv.visitInsn(Opcodes.RETURN);

        // 设置最大栈和局部变量表大小
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }

    /**
     * 生成复杂的add方法
     * 对应Java代码：
     * int add(int a, int b) {
     * int c = a;
     * int d = b;
     * int e = c + d;
     * return e;
     * }
     */
    private static void generateComplexAddMethod(ClassWriter cw) {
        // 方法描述符: (II)I
        MethodVisitor mv = cw.visitMethod(
                Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, // 公共静态方法
                "add",
                "(II)I", // 两个int参数，返回int
                null,
                null
        );

        mv.visitCode();

        // 局部变量表索引：
        // 0: 参数 a
        // 1: 参数 b
        // 2: 局部变量 c
        // 3: 局部变量 d
        // 4: 局部变量 e

        // int c = a;
        mv.visitVarInsn(Opcodes.ILOAD, 0); // 加载参数a
        mv.visitVarInsn(Opcodes.ISTORE, 2); // 存储到局部变量c (索引2)

        // int d = b;
        mv.visitVarInsn(Opcodes.ILOAD, 1); // 加载参数b
        mv.visitVarInsn(Opcodes.ISTORE, 3); // 存储到局部变量d (索引3)

        // int e = c + d;
        mv.visitVarInsn(Opcodes.ILOAD, 2); // 加载局部变量c
        mv.visitVarInsn(Opcodes.ILOAD, 3); // 加载局部变量d
        mv.visitInsn(Opcodes.IADD);        // 执行加法
        mv.visitVarInsn(Opcodes.ISTORE, 4); // 存储结果到局部变量e (索引4)

        // return e;
        mv.visitVarInsn(Opcodes.ILOAD, 4); // 加载局部变量e
        mv.visitInsn(Opcodes.IRETURN);     // 返回结果

        // 设置最大操作数栈大小和局部变量表大小
        // 由于使用了COMPUTE_MAXS，ASM会自动计算这些值
        // 但我们可以手动指定：栈深2（加法操作需要两个操作数），局部变量5
        mv.visitMaxs(2, 5);

        mv.visitEnd();
    }

    /**
     * 加载生成的类
     */
    private static Class<?> loadClass(String className, byte[] bytecode) throws Exception {
        // 使用自定义类加载器
        ClassLoader loader = new ClassLoader() {
            @Override
            protected Class<?> findClass(String name) throws ClassNotFoundException {
                if (name.equals(className)) {
                    return defineClass(name, bytecode, 0, bytecode.length);
                }
                return super.findClass(name);
            }
        };

        return loader.loadClass(className);
    }

    /**
     * 打印生成的字节码
     */
    private static void printBytecode(byte[] bytecode) {
        System.out.println("\nGenerated Bytecode:");
        TraceClassVisitor trace = new TraceClassVisitor(new PrintWriter(System.out));
        new org.objectweb.asm.ClassReader(bytecode).accept(trace, 0);
    }
}